Introducción

¿Que es R?

R es un lenguaje de programación y un entorno de software diseñado específicamente para estadísticas y análisis de datos. Desarrollado por estadísticos y científicos computacionales, R proporciona herramientas robustas para manipular, visualizar y modelar datos, convirtiéndolo en una opción popular entre profesionales en campos como la ciencia de datos, la investigación académica y la analítica empresarial. Su naturaleza de código abierto y la amplia gama de paquetes y extensiones disponibles permiten a los usuarios personalizar y ampliar sus capacidades según sus necesidades específicas. R se destaca por su flexibilidad y potencia en la exploración y comprensión de datos, convirtiéndolo en una herramienta valiosa en el mundo del análisis estadístico.

Importación y Limpieza de Datos

La importación de datos es un proceso crucial en cualquier análisis de datos, ya que la calidad y la precisión de los resultados dependen en gran medida de la calidad de los datos de entrada. La importancia de importar datos desde distintas fuentes radica en la diversidad y complejidad de la información que puede ser crucial para la toma de decisiones informadas

Fuentes (Excel, CSV)

  • Excel: Para importar datos desde archivos Excel, el paquete readxl o openxlsx es comúnmente utilizado. Ejemplo:
# Especificar la ruta del archivo Excel
ruta_archivo <- "01_Informacion_Data/Bureau_Labor_of_Statistics_Data/Detroit_Warren_Dearborn.xlsx"
# Cargar la biblioteca openxlsx para trabajar con archivos Excel
library(openxlsx)

# Leer datos desde la primera hoja del archivo Excel
Employment_1 <- read.xlsx(ruta_archivo, sheet = 1)

# Imprimir los datos cargados para verificar la lectura correcta del archivo

Employment_1

Es frecuente toparse con archivos Excel que presentan encabezados o filas vacías previas a los datos reales. Tanto las bibliotecas readxl como openxlsx brindan una solución sencilla para abordar esta situación.

Aquí tienes un ejemplo utilizando la biblioteca readxl:

# install.packages("readxl")
library(readxl)

# Leer el archivo Excel, omitiendo 10 filas al principio
Employment <- read_excel(
    path = ruta_archivo,
    sheet = "BLS Data Series",
    skip = 10
)
Employment

Este código ejemplifica cómo cargar un archivo Excel, específicamente desde la hoja “BLS Data Series”, omitiendo las primeras 10 filas que contienen encabezados o información no deseada.

  • CSV: La función read.csv() es usada para importar datos desde archivos CSV en R. Ejemplo:
# Especificar la ruta del archivo CSV
file_ruta <- "01_Informacion_Data/Zillow/Zip_zhvi_uc_sfrcondo_tier_0.33_0.67_sm_sa_month.csv"

# Leer el archivo Excel
Zillow <- read.csv(file = file_ruta)

head(Zillow)

Extracción de Datos de Archivos zip

En el ámbito del análisis de datos, la eficiencia y la consistencia en la manipulación de conjuntos de datos son fundamentales. En este contexto, el presente documento explora un script en R diseñado para automatizar la extracción, manipulación y limpieza de datos.

El script aborda la gestión de archivos ZIP que contienen información demográfica clave, extraída de diversas fuentes. A través de una serie de pasos, el código facilita la obtención, procesamiento y consolidación de datos en un formato más manejable y analítico.

El análisis se inicia con la configuración del directorio de trabajo y la identificación de archivos ZIP relevantes. A continuación, se descomprimen estos archivos para revelar conjuntos de datos en formato CSV. Estos datos son entonces leídos, manipulados y agregados en un marco de datos unificado. Además, se realiza una limpieza de archivos temporales para mantener la integridad del espacio de trabajo.

El objetivo de este script es proporcionar una herramienta eficaz para investigadores, analistas y profesionales de datos que deseen analizar y comprender las tendencias demográficas a lo largo del tiempo.

A lo largo del documento, se detallarán cada una de las secciones del código, explicando las decisiones de diseño y brindando orientación sobre cómo adaptar el script a diferentes contextos y conjuntos de datos.

Acompáñenos en este recorrido a través de un proceso automatizado que simplifica la gestión y análisis de datos demográficos del United States Census Bureau en el entorno de programación R.

¡Comencemos!

# Cargar la biblioteca
library(purrr)
library(tidyverse)
library(readr)


# Configuración del directorio y archivos ZIP
my_dir <- "01_Informacion_Data/US_Census_Bureau/"
zip_files <- list.files(path = my_dir, pattern = "*.zip", full.names = TRUE)

# Descomprimir archivos ZIP
unzip_files <- map(zip_files, ~unzip(.x, exdir = my_dir))

En esta sección, se configura el directorio de trabajo y se identifican los archivos ZIP en el directorio. Luego, se descomprimen los archivos ZIP en la misma ubicación.

# Obtener lista de archivos 
data_Lfiles <- list.files(path = my_dir, full.names = TRUE)
data_Lfiles
##  [1] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2011.DP05-Column-Metadata.csv"  
##  [2] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2011.DP05-Data.csv"             
##  [3] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2011.DP05-Table-Notes.txt"      
##  [4] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2011.DP05_2022-10-31T180229.zip"
##  [5] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2012.DP05-Column-Metadata.csv"  
##  [6] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2012.DP05-Data.csv"             
##  [7] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2012.DP05-Table-Notes.txt"      
##  [8] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2012.DP05_2022-11-01T080453.zip"
##  [9] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2013.DP05-Column-Metadata.csv"  
## [10] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2013.DP05-Data.csv"             
## [11] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2013.DP05-Table-Notes.txt"      
## [12] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2013.DP05_2022-11-01T081112.zip"
## [13] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2014.DP05-Column-Metadata.csv"  
## [14] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2014.DP05-Data.csv"             
## [15] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2014.DP05-Table-Notes.txt"      
## [16] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2014.DP05_2022-11-01T081604.zip"
## [17] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2015.DP05-Column-Metadata.csv"  
## [18] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2015.DP05-Data.csv"             
## [19] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2015.DP05-Table-Notes.txt"      
## [20] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2015.DP05_2022-11-01T081827.zip"
## [21] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2016.DP05-Column-Metadata.csv"  
## [22] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2016.DP05-Data.csv"             
## [23] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2016.DP05-Table-Notes.txt"      
## [24] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2016.DP05_2022-11-01T082249.zip"
## [25] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2017.DP05-Column-Metadata.csv"  
## [26] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2017.DP05-Data.csv"             
## [27] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2017.DP05-Table-Notes.txt"      
## [28] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2017.DP05_2022-11-01T082643.zip"
## [29] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2018.DP05-Column-Metadata.csv"  
## [30] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2018.DP05-Data.csv"             
## [31] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2018.DP05-Table-Notes.txt"      
## [32] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2018.DP05_2022-11-01T082752.zip"
## [33] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2019.DP05-Column-Metadata.csv"  
## [34] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2019.DP05-Data.csv"             
## [35] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2019.DP05-Table-Notes.txt"      
## [36] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2019.DP05_2022-11-01T083027.zip"
## [37] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2020.DP05-Column-Metadata.csv"  
## [38] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2020.DP05-Data.csv"             
## [39] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2020.DP05-Table-Notes.txt"      
## [40] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2020.DP05_2022-11-01T083111.zip"
## [41] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2021.DP05-Column-Metadata.csv"  
## [42] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2021.DP05-Data.csv"             
## [43] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2021.DP05-Table-Notes.txt"      
## [44] "01_Informacion_Data/US_Census_Bureau/ACSDP5Y2021.DP05_2023-09-12T103937.zip"
## [45] "01_Informacion_Data/US_Census_Bureau/pop_data.rds"                          
## [46] "01_Informacion_Data/US_Census_Bureau/pop_data.xlsx"
# Obtener archivos de datos en formato CSV
data_files <- list.files(path = my_dir, pattern = "*Data.csv", full.names = TRUE)

# Leer archivos CSV y almacenar en una lista
pop_data <- map(.x = data_files, .f = read.csv, skip = 1, header = TRUE)

# Agregar la columna 'Year' a cada conjunto de datos
for (i in 1:length(pop_data)) {
    pop_data[[i]]$Year <- 2010 + i
}

# Combinar la lista de conjuntos de datos en un marco de datos
pop_data <- map_dfr(.x = pop_data, .f = pluck)

# Seleccionar columnas relevantes
pop_data <- pop_data %>% 
    select(
        Geographic.Area.Name, 
        Estimate..SEX.AND.AGE..Total.population, 
        Year
    )

En esta sección, se identifican los archivos CSV que contienen “Data” en su nombre. Estos archivos se leen y manipulan para agregar una columna ‘Year’ a cada conjunto de datos. Luego, se combinan en un único marco de datos y se seleccionan las columnas relevantes.

# Obtener la lista de archivos .csv y .txt en el directorio
files_to_remove <- list.files(path = my_dir, pattern = "\\.(csv|txt)$", full.names = TRUE)

# Verificar si hay archivos para eliminar
if (length(files_to_remove) > 0) {
    # Eliminar los archivos
    file.remove(files_to_remove)
    cat("Archivos .csv y .txt eliminados correctamente en el directorio:", my_dir)
} else {
    cat("No hay archivos .csv y .txt para eliminar en el directorio:", my_dir)
}
## Archivos .csv y .txt eliminados correctamente en el directorio: 01_Informacion_Data/US_Census_Bureau/
pop_data 

Finalmente, se identifican los archivos temporales (CSV y TXT) y se eliminan. Se proporciona un mensaje indicando si se eliminaron archivos o si no se encontraron archivos para eliminar.

Importación de Datos con Rapid API

Este código en R se desarrolló con el propósito de importar datos mediante una interfaz de programación de aplicaciones (API) para obtener información relacionada con códigos postales en los Estados Unidos.

# Configurar la URL y claves de la API
url <- "https://us-zip-code-to-income.p.rapidapi.com/"
API_Key <- "f7eec58e6cmsh805b1f341c11ff4p18a6b6jsn441ba456adeb" #uwu xd#
API_Host <- "us-zip-code-to-income.p.rapidapi.com"
request_delay <- 2 # Definir el retardo entre las solicitudes (en segundos)

En la sección inicial del código, se establecen las variables esenciales para la configuración de la API. Esto incluye la URL de la API, la clave de autenticación (API_Key), el host de la API (API_Host), y un retardo entre las solicitudes (request_delay) para cumplir con los límites de la API y evitar posibles restricciones.

# missing_zip_codescrime_zip que se quiere extraer de la API
missing_zip_codescrime_zip <- c("48430", "48211", "48760", "48139", "48440")
# Cargar la biblioteca
library(httr)
library(jsonlite)
library(tidyverse)
library(fs)
library(rvest)
library(xml2)
library(readxl)
library(dplyr)
# Definir una función para importar datos utilizando la API
data_import_IP <- function(url, API_Key, API_Host, request_delay) {
    
    data_df <- tibble()
    
    for (i in seq_along(missing_zip_codescrime_zip)) {
        
        query_params <- list(zip = missing_zip_codescrime_zip[i])
        
        # Realizar la solicitud GET a la API
        response <- GET(url, add_headers("X-RapidAPI-Key" =  API_Key, "X-RapidAPI-Host" = API_Host), query = query_params)
        
        # Verificar el estado de la respuesta
        stop_for_status(response)
        
        # Convertir la respuesta JSON a un marco de datos
        cont_response <- fromJSON(rawToChar(response$content))
        
        # Concatenar el marco de datos resultante
        data_df <- bind_rows(data_df, as_tibble(cont_response))
        
        # Imprimir información sobre el código postal procesado
        print(str_glue("Zip Code: {missing_zip_codescrime_zip[i]}"))
        
        # Retardo entre las solicitudes para evitar límites de la API
        Sys.sleep(request_delay)
    }
    
    # Nombrar las columnas del marco de datos resultante
    colnames(data_df) <- c("success", "zip", "House Hold Median Income", "household MeanIncome", "familyMedianIncome", "familyMeanIncome", "numHouseholds", "nonFamilyHousehold MedianIncome", "nonFamilyHouseholdMeanIncome", "familyPercentPoverty")
    
    return(data_df)
}

La función ‘data_import_IP’ tiene como objetivo principal realizar solicitudes a una API para obtener información relacionada con códigos postales en los Estados Unidos. Aquí está una explicación paso a paso de lo que hace la función:

1.Inicialización del Marco de Datos:

  • Se crea un marco de datos vacío llamado ‘data_df’ utilizando la función ‘tibble()’ que se utilizará para almacenar los resultados de las solicitudes a la API.

2.Bucle de Importación de Datos:

  • La función utiliza un bucle ‘for’ para iterar sobre cada código postal en la secuencia ‘missing_zip_codescrime_zip’. Este bucle permite procesar cada código postal de manera individual.

3.Construcción de Parámetros de Consulta:

  • Para cada código postal, se construye un conjunto de parámetros de consulta denominado ‘query_params’. Este conjunto incluye el código postal actual y se utiliza en la solicitud a la API.

4.Solicitud GET a la API:

  • Se realiza una solicitud GET a la API utilizando la función ‘GET’. La URL de la API, las cabeceras de autenticación (‘X-RapidAPI-Key’ y ‘X-RapidAPI-Host’), y los parámetros de consulta se utilizan en la solicitud. La respuesta de la API se almacena en la variable ‘response’.

5.Procesamiento de la Respuesta JSON:

  • La respuesta en formato JSON se convierte a un formato tabular utilizando la función ‘fromJSON’ del paquete ‘jsonlite’. El resultado se almacena en el objeto ‘cont_response’.

6.Concatenación de Resultados:

  • Los resultados de cada solicitud se concatenan al marco de datos existente (‘data_df’) utilizando la función ‘bind_rows’.

7.Impresión de Información del Código Postal:

  • Se imprime información descriptiva sobre el código postal procesado, utilizando la función ‘print(str_glue(“Zip Code: {missing_zip_codescrime_zip[i]}”))’. Esto facilita el seguimiento del progreso y la identificación de los códigos postales procesados.

8.Retardo entre Solicitudes:

Para cumplir con las políticas de velocidad de la API y evitar exceder límites, se introduce un retardo de tiempo (‘Sys.sleep(request_delay)’) entre cada solicitud.

9.Nombrar Columnas del Marco de Datos Resultante:

  • Se asignan nombres descriptivos a las columnas del marco de datos resultante (‘data_df’) para una interpretación más clara de los datos.

10.Retorno del Resultado:

  • La función retorna el marco de datos final (data_df), que contiene la información recopilada de todas las solicitudes a la API.
# Llamar a la función de importación de datos utilizando la API
result_df <- data_import_IP(url, API_Key, API_Host, request_delay)
## Zip Code: 48430
## Zip Code: 48211
## Zip Code: 48760
## Zip Code: 48139
## Zip Code: 48440
result_df

Organización Modular en R: Creación y Aplicación de Funciones Personalizadas

En R, puedes crear tus propias funciones y guardarlas en un script separado para luego poder utilizarlas en otros scripts. Aquí hay un ejemplo paso a paso:

1.Crea tu función en un script: * Abre un nuevo script en R (puedes usar un editor de texto o un entorno de desarrollo como RStudio). Define tu función y guárdala en el script. Por ejemplo, crea un archivo llamado misFunciones.R con el siguiente contenido:

# misFunciones.R

sumaDosNumeros <- function(a, b) {
  resultado <- a + b
  return(resultado)
}

2.Guarda el script: * Guarda el script con el nombre que hayas elegido, en este caso, ‘misFunciones.R’.

3.Usa la función en otro script: * En otro script o en la consola de R, puedes cargar el script que contiene tus funciones usando la función ‘source’. Aquí hay un ejemplo:

# scriptPrincipal.R

# Cargar el script que contiene las funciones
> source("misFunciones.R")

# Ahora puedes utilizar la función en este script
> resultado_suma <- sumaDosNumeros(3, 5)
> print(resultado_suma)

Almacenando de data

En estas líneas de código se utilizan para almacenar el objeto ‘pop_data’ en un archivo RDS y luego cargarlo de nuevo en el entorno de trabajo de R en el objeto ‘pop_data’. Este proceso es útil para persistir datos entre sesiones de trabajo o compartir datos de manera eficiente, ya que el formato RDS conserva la estructura y los tipos de datos del objeto original.

# Guardar en archivo RDS
rds_file <- file.path(my_dir, "pop_data.rds")
saveRDS(pop_data, rds_file)

# Cargar el archivo RDS en un objeto llamado pop_data
pop_data <- readRDS(file.path(my_dir, "pop_data.rds"))

Manipulación y Preparación de Datos

Comparación de Data Frames

# Definir valores de prueba para DWD_MI_Zip y crime_zip
DWD_MI_Zip <- c("10001", "20002", "30303", "40004", "50005")
crime_zip <- c("10001", "30303", "50005", "60006", "70007")

# Comprobar si los conjuntos de códigos postales son idénticos
identical_result <- identical(DWD_MI_Zip, crime_zip)
print(paste("Los conjuntos son idénticos:", identical_result))
## [1] "Los conjuntos son idénticos: FALSE"

La función identical() se utiliza para verificar si dos objetos son idénticos entre sí. La función devuelve un valor lógico (TRUE o FALSE) según si los objetos son idénticos o no.

# Mostrar los códigos postales que faltan en cada conjunto
missing_DWD_MI_Zip <- DWD_MI_Zip[!DWD_MI_Zip %in% crime_zip]
missing_crime_zip <- crime_zip[!crime_zip %in% DWD_MI_Zip]

print("Códigos postales que faltan en DWD_MI_Zip:")
## [1] "Códigos postales que faltan en DWD_MI_Zip:"
print(missing_DWD_MI_Zip)
## [1] "20002" "40004"
print("Códigos postales que faltan en crime_zip:")
## [1] "Códigos postales que faltan en crime_zip:"
print(missing_crime_zip)
## [1] "60006" "70007"

Este código en R tiene como objetivo identificar y mostrar los códigos postales que faltan en dos conjuntos de datos, DWD_MI_Zip y crime_zip. Utiliza la función %in% para realizar la comparación entre los dos conjuntos y determinar los elementos que no están presentes en ambos.

Transformar y formatear datos

La librería scales en R proporciona funciones para transformar y formatear datos, especialmente útiles para la visualización de gráficos. Aquí hay un resumen de las principales funciones y utilidades proporcionadas por scales:

# Cargar la biblioteca
library(scales)

# Numero de prueba
number <- 5.1234567

# Formato de dolares
number |> 
    scales::dollar()
## [1] "$5.12"
# Formateo de Números como Porcentajes
number |> 
    scales::percent(accuracy = 0.01)
## [1] "512.35%"
# Crear un vector de fechas
dates <- as.Date(c("2022-01-15 12:30:00", "2022-02-20 15:45:00", "2022-03-25 18:15:00"))

# Formatear las fechas en el estilo "día de la semana, mes día, año"
formatted_dates <- date_format("%A, %B %d, %Y")(dates)
print(formatted_dates)
## [1] "sábado, Enero 15, 2022"    "domingo, Febrero 20, 2022"
## [3] "viernes, Marzo 25, 2022"
# Crear un vector de horas
times <- as.POSIXct(c("2022-01-15 12:30:00", "2022-02-20 15:45:00", "2022-03-25 18:15:00"))

# Formatear las horas en el estilo "hora:minuto AM/PM"
formatted_times <- time_format("%I:%M %p")(times)
print(formatted_times)
## [1] "05:30 p. m." "08:45 p. m." "11:15 p. m."
# Crear un vector de fechas y horas
datetime <- as.POSIXct(c("2022-01-15 12:30:00", "2022-02-20 15:45:00", "2022-03-25 18:15:00"))

# Formatear las fechas y horas en el estilo "día de la semana, mes día, año hora:minuto AM/PM"
formatted_datetime <- date_format("%A, %B %d, %Y %I:%M %p")(datetime)
print(formatted_datetime)
## [1] "sábado, Enero 15, 2022 05:30 p. m."   
## [2] "domingo, Febrero 20, 2022 08:45 p. m."
## [3] "viernes, Marzo 25, 2022 11:15 p. m."

Filtrar datos

En R, la función ‘filter’ se utiliza comúnmente para extraer filas específicas de un conjunto de datos basándose en condiciones específicas. Aquí tienes algunos ejemplos de cómo usar la función ‘filter’:

library(dplyr)
# Crear un ejemplo de dataframe
df <- data.frame(
  ID = c(1, 2, 3, 4, 5, 6),
  Name = c("Alice", "Bob", "Charlie", "David", "Eva", "Fernanda"),
  Age = c(25, 30, 22, 35, 28, NaN),
  Gender = c("Female", "Male", "Male", "Male", "Female", "Female")
)

df
  • Filtrar basado en una condición numérica
# Filtrar personas mayores de 25 años
result <- filter(df, Age > 25)

result
  • Filtrar basado en una condición de texto
# Filtrar personas de género femenino
result <- filter(df, Gender == "Female")

result
  • Filtrar utilizando múltiples condiciones
# Filtrar personas mayores de 25 años y de género femenino
result <- filter(df, Age > 25 & Gender == "Female")

result
  • Filtrar valores faltantes
library(naniar)
# Resumen de valores faltantes en el conjunto de datos filtrado
miss_val_resumen <- df |>
  miss_case_summary()

# Imprimir el resumen
miss_val_resumen

Uso de mutate

La función mutate() es parte del paquete dplyr en R y se utiliza para realizar transformaciones en columnas existentes o agregar nuevas columnas a un conjunto de datos. Esta función es comúnmente utilizada en el contexto de manipulación y transformación de datos.

# Instala e carga las librerías necesarias si no las has instalado
library(dplyr)
library(lubridate)

# Crear un conjunto de datos ficticio con una columna de fechas
datos <- data.frame(
  Date_chr = c("2022-01-15", "2021-08-22", "2023-03-10")
)

# Utilizar mutate() y year() para crear una nueva columna "Year"
datos_con_year <- datos %>%
  mutate(Year = year(ymd(Date_chr)))

# Imprimir el conjunto de datos resultante
datos_con_year

Técnicas de Fusión y Transformaciones

# Crear ejemplo de df1
df1 <- data.frame(
  ID = c(1, 2, 3, 4, 2, 3, 4),
  Nombre = c("Alice", "Bob", "Charlie", "David","Bob", "Charlie", "David"),
  Apellido = c("Smith", "Johnson", "Garcia", "Fisher","Johnson", "Garcia", "Fisher")
)

# Crear ejemplo de df2
df2 <- data.frame(
  ID = c(2, 3, 4, 5, 3, 4, 2),
  Ventas = c(2250, 5047, 5461, 7539, 2250, 5047, 5461)
)
  • Fusión de DF
# Ejemplo de fusión 

merged_df <- df1 |>
  full_join(df2, by = "ID")

merged_df
  • Agrupacion
# Ejemplo de agrupación y resumen 

ventas_resumen <- merged_df %>%
  group_by(Nombre) %>%
  summarise(Total_Ventas = sum(Ventas))

ventas_resumen
  • Combinación de columnas
# Ejemplo de combinación de columnas
merged_df <- merged_df %>%
  mutate(Nueva_Columna = paste(Nombre, Apellido, sep = "-"))

merged_df

Selección de Información Relevante

# Seleccionar solo las columnas "Nombre" y "Ventas"
datos_seleccionados <- select(merged_df, Nombre, Ventas)

# Imprimir el dataframe resultante
datos_seleccionados

Visualizaciones de Datos

Los gráficos desempeñan un papel fundamental en el análisis de datos y la visualización de resultados en el ámbito de la programación estadística, y R se destaca como un lenguaje de programación especialmente poderoso para la creación de gráficos.

# Cargar bibliotecas necesarias
library(readxl)
library(tidyverse)
library(naniar)
library(lubridate)
library(stringr)
library(fs)
library(scales)
library(ggplot2)
library(plotly)
library(tidyquant)
library(ggrepel)

# Fuente de las funciones personalizadas
source("06_funciones_y_interacion_iteration/Zillow_PC_Function.R")
source("06_funciones_y_interacion_iteration/funciones_de_importacion.R")

# Obtener datos de ciudades con la Tasa de Crecimiento Anual Compuesta (CAGR) para los años 2000 a 2022
CAGR_Data <- getTopCitiesByCAGR(2000, 2022, 30)

# Importar datos del Índice del Mercado Inmobiliario de Zillow (ZMI)
ZMI_Data_Prep <- data_import("ZMI_data_pre")

# Combinar los marcos de datos CAGR_Data y ZMI_Data_Prep en la columna "City_zip"
ZillowTrends <- CAGR_Data |> left_join(ZMI_Data_Prep, by = "City_zip")

ZillowTrends

Exploración de datos perdidos

Utilizando la función ‘gg_miss_var’ de la biblioteca ‘naniar’ para visualizar los valores perdidos en los datos.

# Grafico de valores faltantes
ZillowTrends |> gg_miss_var()

Apreciación de Precios de Viviendas Año tras Año

# Seleccionar las columnas relevantes en el marco de datos ZillowTrends
ZillowTrends <- ZillowTrends |>
    select(City_zip, Year, Z_Home_Value_Index, ZHVI_PC_YoY, ZHVI_PC_YoY_chr, timeperiod, Number_of_Years, CAGR)

# Calcular la tasa de crecimiento promedio (CAGR) para todos los datos
ave_rate <- ZillowTrends |>
    pull(CAGR) |>
    mean() |>
    scales::percent(accuracy = 0.01)

# Obtener el año mínimo y máximo en el conjunto de datos ZillowTrends
min_y <- ZillowTrends |>
    pull(Year) |>
    min()

max_y <- ZillowTrends |>
    pull(Year) |>
    max()

# Agregar una nueva columna 'tool_tip' con información para etiquetas emergentes
ZillowTrends <- ZillowTrends |>
    mutate(tool_tip = str_glue("CityZip: {City_zip},
                               %Change: {ZHVI_PC_YoY_chr},
                               Year: {Year}"))

# Crear un gráfico ggplot
g <- ZillowTrends |> ggplot(aes(x = Year, y = ZHVI_PC_YoY, color = City_zip, text = tool_tip, group = City_zip)) +
    geom_line(linewidth = 1) +
    geom_point(size = 2, alpha = 0.5) +
    geom_hline(yintercept = 0, linetype = "dashed", color = "black", linewidth = 0.50) +
    labs(
        title = "Apreciación de Precios de Viviendas Año tras Año",
        subtitle = str_glue("Cambio porcentual YoY de {min_y} a {max_y}"),
        x = "AÑO",
        y = "Cambio Porcentual (%)",
        caption = str_glue("De {min_y} a {max_y}, la CAGR promedio ha sido {ave_rate} \n para estos 30 principales códigos postales en el Área Metropolitana de Detroit")
    )

# Mostrar el gráfico
g

##Convierte el gráfico a un gráfico interactivo

Convierte el gráfico creado con ggplot2 a un gráfico interactivo utilizando plotly y especifica que las etiquetas de herramientas deben tomarse de la columna ‘tool_tip’.

## Gráfico interactivo
g |> 
    ggplotly(tooltip = "tool_tip") 

Apreciación de Precios de Viviendas Año tras Año 2

# Crear un gráfico ggplot con facetas (Plot 2)
g <- ZillowTrends |> ggplot(aes(x = Year, y = ZHVI_PC_YoY, color = City_zip, text = tool_tip, group = City_zip)) +
    geom_line(linewidth = 1) +  # Agregar líneas para representar los datos
    geom_point(size = 2, alpha = 0.5) +  # Agregar puntos para representar los datos
    geom_hline(yintercept = 0, linetype = "dashed", color = "black", linewidth = 0.50) +  # Agregar línea horizontal en y=0
    facet_wrap(~ City_zip, scales = "free_y") +  # Facetar el gráfico por código postal con escalas independientes en el eje y
    labs(
        title = "Apreciación de Precios de Viviendas Año tras Año",
        subtitle = str_glue("Cambio porcentual YoY de {min_y} a {max_y}"),
        x = "AÑO",
        y = "Cambio Porcentual (%)",
        caption = str_glue("De {min_y} a {max_y}, la CAGR promedio ha sido {ave_rate} \n para estos 30 principales códigos postales en el Área Metropolitana de Detroit")
    ) +
    theme_minimal() +  # Puedes ajustar el tema según tus preferencias
    theme(
        plot.title = element_text(size = 20, face = "bold"),
        axis.title.x = element_text(size = 16),
        axis.title.y = element_text(size = 16),
        axis.text.x = element_text(size = 6),
        axis.text.y = element_text(size = 6),
        legend.text = element_text(size = 12)
    ) +
    guides(color = guide_legend(override.aes = list(size = 4)))  # Ajustar el tamaño de la leyenda

g

# Convertir el gráfico ggplot a una versión interactiva usando plotly
g_plotly <- g |> ggplotly(tooltip = "tool_tip")

# Ajustar el tamaño del gráfico plotly
g_plotly <- g_plotly %>%
    config(displayModeBar = TRUE) %>%  # Puedes desactivar la barra de herramientas si lo prefieres
    layout(width = 1000, height = 600)  # Ajustar el tamaño según tus preferencias

# Mostrar el gráfico plotly
g_plotly

Precios de Viviendas vs Empleo

# Importar datos relevantes para el Plot 3
ZMI_Data_Prep
Employment_C <- data_import("Employment_C")

# Calcular el promedio del cambio porcentual YoY del índice de valor de la vivienda (ZHVI_PC_YoY) por año
avg_zhvi_pc_by_year <- ZMI_Data_Prep |>
    group_by(Year) |> 
    summarise("Home Value Index" = ZHVI_PC_YoY |> mean())

# Combinar datos de empleo y datos del índice de valor de la vivienda por año
homev_vs_Job_growth <- Employment_C |>
    left_join(avg_zhvi_pc_by_year, by = "Year") |>
    select(Year, PC_YoY, "Home Value Index") |>
    mutate("Employment in Metro Detroit" = PC_YoY) |>
    gather(key = "Legend", value = "Percentage_Change", "Employment in Metro Detroit", "Home Value Index")

# Modificar el formato de porcentaje y la etiqueta del texto
homev_vs_Job_growth <- homev_vs_Job_growth |>
    mutate(PC_YoY_chr = Percentage_Change |> scales::percent(accuracy = 0.01)) |>
    mutate(Percentage_Change = (Percentage_Change * 100)) |>
    mutate(label_text = str_glue("Legend:{Legend},
                                 Year:{Year},
                                 Percentage:{PC_YoY_chr}"))

# Calcular el número de códigos postales únicos en ZMI_Data_Prep
num_of_zip <- ZMI_Data_Prep |> select(City_zip) |> unique() |> nrow()

# Crear el gráfico ggplot para el Plot 3
p3 <- homev_vs_Job_growth |>
    drop_na(Percentage_Change) |>
    ggplot(aes(x = Year, y = Percentage_Change, linetype = Legend, colour = Legend, label = label_text)) +
    geom_line(linewidth = 1) +
    geom_point(aes(text = label_text), size = 2) +
    geom_hline(yintercept = 0, linetype = "dashed", color = "gray0", size = 0.50)+
    labs(
        title = "Precios de Viviendas vs Empleo",
        subtitle = "Cambio Porcentual YoY entre Precios de Viviendas y Empleo",
        y = "Cambio Porcentual (%)",
        caption = str_glue("Las fuentes de datos son 'Zillow' y 'Bureau of Labor Statistics'.
        Los datos de empleo son del área de Empleo de Detroit-Warren-Dearborn. 
        El Índice de Valor de la Vivienda es la media del cambio de {num_of_zip} códigos postales en el área de Detroit-Warren-Dearborn.'"
    )) +
    theme_light()

# Convertir el gráfico ggplot a una versión interactiva usando plotly
p3_plotly <- p3 |> ggplotly(tooltip = "text")

# Mostrar el gráfico plotly
p3_plotly
p3 + scale_colour_brewer(palette = "Set1")

p3 + theme (
    
    plot.title    = element_text(color="dark blue", size = 12, face = "bold"),
    plot.subtitle = element_text(color="dark blue", size = 10, face = "italic"),
    plot.caption  = element_text(color="dark blue", size = 8, face = "bold.italic")
)    

Regresión LOESS

## (LOESS) Local Polynomial Regression

# Combinar datos de empleo y datos del índice de valor de la vivienda por año
homev_vs_Job_growth_II <- Employment_C |>
    left_join(avg_zhvi_pc_by_year, by = "Year") |>
    select(Year, PC_YoY, "Home Value Index") |>
    mutate(Employment = PC_YoY) |>
    mutate(Home_Value_Index = `Home Value Index`) |>
    filter(Year > 1999)

# Ajustar un modelo LOESS (Local Polynomial Regression)
mod <- loess(Home_Value_Index ~ Employment, data = homev_vs_Job_growth_II)
grid <- tibble(Employment = seq(min(homev_vs_Job_growth_II$Employment), max(homev_vs_Job_growth_II$Employment), length = 50))
grid$Home_Value_Index <- predict(mod, newdata = grid)

# Calcular residuos estandarizados y identificar valores atípicos
std_resid <- resid(mod) / mod$s
outlier <- filter(homev_vs_Job_growth_II, abs(std_resid) > 1)
outlier
# Crear un gráfico ggplot para el modelo LOESS

p4 <- ggplot(homev_vs_Job_growth_II, aes(Employment, Home_Value_Index)) +
    geom_point() +
    geom_line(data = grid, colour = "blue", size = 1.5) + 
    ggrepel::geom_text_repel(data = outlier, aes(label = Year)) +
    
    labs(
        title = "Regresión LOESS",
        y = "Cambio Promedio % Índice de Valor de la Vivienda",
        x = "Cambio Promedio % Empleo",
        caption = "La regresión LOESS, a veces llamada regresión local, es un método que utiliza el ajuste local para ajustar un modelo de regresión a un conjunto de datos"
    )

# Añadir anotaciones al gráfico
p4 + annotate(geom = "curve",
              x = -0.10,
              y = 0.09,
              xend = -0.106,
              yend = 0.055,
              curvature = 0.3, arrow = arrow(length = unit(2, "mm"))) +
    annotate(geom = "text", x = -0.10, y = 0.09, label = "Pandemia Global", hjust = "left")

## LOESS & ggplotly

# Modificar el formato de porcentaje y la etiqueta del texto para ggplotly
homev_vs_Job_growth_II <- homev_vs_Job_growth_II |>
    mutate(Home_Value_Index_ch = Home_Value_Index |> scales::percent(accuracy = 0.01)) |>
    mutate(Employment_ch = PC_YoY |> scales::percent(accuracy = 0.01)) |>
    mutate(label_text  = str_glue("Year: {Year},
                                   Home Value Index: {Home_Value_Index_ch},
                                   Employment: {Employment_ch}"))

# Crear un gráfico ggplotly interactivo
p4 <- ggplot(homev_vs_Job_growth_II, aes(Employment, Home_Value_Index)) +
    geom_point(aes(text = label_text), size = 2) +
    geom_line(data = grid, colour = "blue", size = 1.5) + 
    ggrepel::geom_text_repel(data = outlier, aes(label = Year)) +
    
    labs(
        title = "Regresión LOESS",
        y = "Cambio Promedio % Índice de Valor de la Vivienda",
        x = "Cambio Promedio % Empleo",
        caption = "La regresión LOESS, a veces llamada regresión local, es un método que utiliza el ajuste local para ajustar un modelo de regresión a un conjunto de datos"
    ) +
    scale_y_continuous(labels = scales::percent) +
    scale_x_continuous(labels = scales::percent)

# Convertir el gráfico ggplotly a una versión interactiva
p4 |>
    ggplotly(tooltip = "text")

Explorando Mercados Inmobiliarios: Usando Geom_Bar

# Crear un conjunto de datos combinando datos de empleo y datos del índice de valor de la vivienda por año (Plot 5)
homev_vs_Job_growth_III <- Employment_C |>
    left_join(avg_zhvi_pc_by_year, by = "Year") |>
    select(Year, PC_YoY, "Home Value Index") |>
    mutate(Employment = PC_YoY) |>
    mutate(Home_Value_Index = `Home Value Index`)

# Añadir nuevas columnas con porcentajes y texto para etiquetas
homev_vs_Job_growth_III <- homev_vs_Job_growth_III |>
    mutate(Home_Value_Index_PC = `Home Value Index` |> scales::percent(accuracy = 0.01)) |>
    mutate(Employment_PC = PC_YoY |> scales::percent(accuracy = 0.01)) |>
    mutate(label_text1 = str_glue("Employment: {Employment_PC}")) |>
    mutate(label_text2 = str_glue("Home Value Index: {Home_Value_Index_PC}")) |>
    mutate(label_text3 = str_glue("E: {Employment_PC}%")) |>
    mutate(label_text4 = str_glue("H: {Home_Value_Index_PC}%"))

# Obtener el rango de años
miny <- homev_vs_Job_growth_III |> pull(Year) |> min()
max_y <- homev_vs_Job_growth_III |> pull(Year) |> max()

# Crear un gráfico de barras apiladas
p5 <- ggplot(homev_vs_Job_growth_III) +
    geom_bar(
        aes(Year, Employment, text = label_text1),
        stat = "identity",
        position = "dodge",
        fill = "cadetblue1",
        color = "black"
    ) +
    
    geom_bar(
        aes(Year, Home_Value_Index, text = label_text2),
        stat = "identity",
        position = "dodge",
        fill = "navy",
        color = "black",
        alpha = 0.3
    ) +
    
    scale_y_continuous(labels = scales::percent) +
    
    labs(
        title = "Precios de Viviendas vs Empleo",
        caption = str_glue("Fuentes de datos: Zillow y Bureau Labor of Statistics \n Marco temporal: {min_y} {max_y}")
    ) +
    
    geom_label(
        aes(Year, Employment, label = label_text3),
        hjust = "left",
        vjust = "top",
        size = 3
    ) +
    
    geom_label(
        aes(Year, Home_Value_Index, label = label_text4),
        hjust = "right",
        vjust = "bottom",
        size = 3
    )

# Convertir el gráfico ggplot a una versión interactiva usando plotly
p5 |> ggplotly(tooltip = "text") |> 
    layout(
        title = list(
            text = paste(
                'Precios de Viviendas vs Empleo',
                '<br>',
                '<sup>',
                '<b>', 'Fuentes de datos:',
                '</b>', "(Zillow) & (Bereau Labor of Statistics)",
                '</sup>'
            )
        )
    )

Representación Gráfica del Ingreso Medio Familiar

# Extraer códigos postales y convertirlos a formato entero
CAGR_Data_zip <- CAGR_Data |>
    mutate(zip = str_extract(City_zip, pattern = "\\d{5}")) |>
    mutate(zip = zip |> as.integer())

# Importar datos demográficos
demographics <- data_import(dataSource = "Demographis")

# Combinar datos de CAGR con datos demográficos utilizando códigos postales
demographics_CAGR <-  CAGR_Data_zip |> left_join(demographics, by = "zip")

# Visualizar la estructura de datos
demographics_CAGR |> glimpse()
## Rows: 30
## Columns: 16
## $ City_zip                       <glue> "Detroit_48201", "Detroit_48209", "Det…
## $ Beginning_Value                <dbl> 85994.28, 17091.93, 17041.83, 20307.30,…
## $ Ending_Value                   <dbl> 454612.78, 82906.16, 62032.72, 63603.83…
## $ timeperiod                     <chr> "2000-2022", "2000-2022", "2000-2022", …
## $ Number_of_Years                <dbl> 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,…
## $ CAGR                           <dbl> 0.07862742, 0.07441617, 0.06048554, 0.0…
## $ zip                            <int> 48201, 48209, 48210, 48218, 48212, 4803…
## $ success                        <chr> "true", "true", "true", "true", "true",…
## $ House_Hold_Median_Income       <int> 21180, 34104, 33711, 24034, 32439, 5087…
## $ houseHoldMeanIncome            <int> 47405, 47947, 43855, 39400, 43899, 5965…
## $ familyMedianIncome             <int> 29432, 39947, 39104, 32877, 37337, 5856…
## $ familyMeanIncome               <int> 64410, 54050, 49250, 52961, 47899, 6575…
## $ numHouseholds                  <int> 7741, 9081, 8031, 2894, 11484, 6801, 89…
## $ nonFamilyHouseholdMedianIncome <int> 18331, 19924, 25139, 16829, 23926, 3598…
## $ nonFamilyHouseholdMeanIncome   <int> 40064, 30109, 31137, 25584, 32962, 5086…
## $ familyPercentPoverty           <dbl> 52.52, 38.98, 40.76, 49.66, 44.16, 25.6…
# Agregar una columna de texto para etiquetas
demographics_CAGR <- demographics_CAGR |>
    mutate(label_text = str_glue("Household Median Income: {House_Hold_Median_Income |> scales::dollar()}"))

# Crear un gráfico de barras
p6 <- ggplot(demographics_CAGR, aes(x = reorder(City_zip, -House_Hold_Median_Income))) +
    geom_bar(
        aes(y = House_Hold_Median_Income, text = label_text),
        stat = "identity",
        color = "black", fill = "skyblue"
    ) +
    scale_y_continuous(name = "Median Income", labels = scales::dollar) +
    labs(x = "ZipCode") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 90))

# Convertir el gráfico ggplot a una versión interactiva usando plotly
g_plotly <- p6 |> ggplotly(tooltip = "label_text") |> 
    layout(
        title = list(
            text = paste0('<br>',
                          'Household Median Income',
                          '</br>',
                          '<br>',
                          '<sup>',
                          '<b>',
                          'Note:',
                          '</b>', 'These ZipCodes have the higher CAGR in Metro Detroit',
                          '</sup>')
        )
    )

# Ajustar el tamaño del gráfico plotly
g_plotly <- g_plotly %>%
    config(displayModeBar = TRUE) %>%  # Puedes desactivar la barra de herramientas si lo prefieres
    layout(width = 1000, height = 600)  # Ajustar el tamaño según tus preferencias

# Mostrar el gráfico plotly
g_plotly

Gráfico de Pareto Clásico

El Gráfico de Pareto es una herramienta visual poderosa utilizada en gestión y mejora de procesos para identificar y priorizar problemas o causas, centrándose en aquellos que tienen el mayor impacto. Su nombre proviene del principio de Pareto, que sugiere que aproximadamente el 80% de los problemas provienen del 20% de las causas.

# Data Preparation
data <- data.frame(
    Category = c("Dose Missed",
                 "Wrong Time",
                 "Overdose",
                 "Wrong Patient",
                 "Wrong Drug",
                 "Wrong Calculation",
                 "Duplicated Dose",
                 "Under Dose",
                 "Wrong Rate",
                 "Technique Error",
                 "Unauthorized Drug"),
    Frequency = c(92, 83, 76, 59, 53, 27, 16, 9, 7, 4, 3)
)

# Ordenar los datos por frecuencia en orden descendente
data <- data |>
    arrange(desc(Frequency)) |>
    # Calcular la suma acumulativa y el porcentaje acumulativo
    mutate(Cumulative = cumsum(Frequency)) |>
    mutate(Cumulative_Percent = Cumulative / sum(Frequency) * 100)

# Crear un gráfico de barras y línea (Pareto Chart)
p <- ggplot(data, aes(x = reorder(Category, -Frequency), y = Frequency)) +
    geom_bar(
        aes(text = paste("Category:", Category, "<br>Frequency:", Frequency)),
        stat = "identity",
        fill = "blue"
    ) +
    geom_line(
        aes(y = Cumulative_Percent,
            group = 1,
            text = paste("Category:", Category, "<br>Cumulative %:", sprintf("%.2f", Cumulative_Percent))),
        colour = "red"
    ) +
    geom_point(
        aes(y = Cumulative_Percent,
            text = paste("Category:", Category, "<br>Cumulative %:", sprintf("%.2f", Cumulative_Percent))),
        colour = "red"
    ) +
    # Agregar una línea de referencia en el 80% para el Pareto
    geom_hline(aes(yintercept = 80), linetype = "dashed", color = "green") +
    # Agregar eje secundario para el porcentaje acumulativo
    scale_y_continuous(sec.axis = sec_axis(~ ., name = "Cumulative %")) +
    theme_minimal() +
    labs(
        x = "Type of Medication Errors",
        y = "Frequency #",
        title = str_glue("Pareto Chart Types of Medication Errors (n = {data$Frequency |> sum()})")
    ) +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Convertir el gráfico ggplot a una versión interactiva usando plotly
p |>
    ggplotly(tooltip = "text")

Modelos con LOWESS

LOWESS, que significa “locally weighted scatterplot smoothing” (alisado de gráficos de dispersión ponderado localmente), es un método estadístico utilizado para realizar un suavizado local en datos bidimensionales. LOWESS es un tipo de modelo no paramétrico que se utiliza para explorar la relación entre dos variables, generalmente representadas en un gráfico de dispersión.

El método LOWESS suaviza los datos mediante la aplicación de pesos locales a los puntos de datos en función de su proximidad espacial. Esto significa que el suavizado en cada punto se realiza teniendo en cuenta principalmente los puntos cercanos y asignando pesos más bajos a los puntos más alejados. De esta manera, el modelo se adapta localmente a la variabilidad de los datos y proporciona un suavizado más flexible que algunos métodos globales de suavizado.

Para aplicar el modelo LOWESS, se selecciona un parámetro llamado “ancho de banda” que determina la ventana alrededor de cada punto que se utilizará para calcular el suavizado local. Un ancho de banda más grande incluirá más puntos en el cálculo, lo que dará como resultado un suavizado más suave pero menos sensible a las variaciones locales.

LOWESS es útil en la exploración visual de datos para identificar tendencias o patrones subyacentes, especialmente cuando los datos muestran variabilidad significativa. Este método ha sido utilizado en diversas disciplinas, como estadísticas, econometría y ciencias sociales, para comprender mejor la relación entre variables y detectar tendencias locales en datos ruidosos.

# Carga de bibliotecas ----
library(tidyverse)  # Paquete para manipulación y visualización de datos
library(lubridate)  # Paquete para manipulación de fechas
library(stringr)    # Paquete para manipulación de cadenas de texto
library(fs)         # Paquete para operaciones con el sistema de archivos
library(scales)     # Paquete para escalas personalizadas en gráficos

# Carga de la biblioteca ggplot2 si no está cargada
library(ggplot2)

# Establecer una semilla para reproducibilidad
set.seed(13)

# Generar datos de ejemplo ----
x <- seq(1, 200, length.out = 200)  # Secuencia de valores para x
y <- sin(x/10) + rnorm(200, 0, 0.5)  # Función seno con ruido aleatorio

# Aplicar suavizado LOESS ----
smoothed_data <- lowess(x, y)

# Graficar los datos originales y suavizados ----
P1 <- ggplot(mapping = aes(x = x, y = y)) +
    geom_point(color = "blue") +
    geom_line(aes(y = smoothed_data$y), color = "red") +
    ggtitle("LOESS")

P1

# Generar tress modelos con diferentes spans
# Entre mas bajo el span mas alta la posibilidad de overfitting
# Cross validation para encontrar el mejor span

model1 <- loess(y ~ x, span = 0.2)
model2 <- loess(y ~ x, span = 0.5)
model3 <- loess(y ~ x, span = 0.8)

# Grafico de comparacion de modelos ----

FP <- ggplot(mapping = aes(x = x, y = y)) +
    geom_point(color = "blue") +
    geom_line(aes (y = fitted (model1)), color = "red")+
    geom_line(aes (y = fitted (model2)), color = "black")+
    geom_line(aes (y = fitted (model3)), color = "yellow")+
    ggtitle("LOESS")

library(plotly)
FP |> ggplotly()

Manejar Valores atípicos

La importancia de gestionar valores atípicos radica en varios aspectos clave. En primer lugar, estos valores pueden distorsionar las medidas estadísticas comunes, como la media y la desviación estándar, generando estimaciones sesgadas y poco representativas de la realidad. Al abordar los valores atípicos, se obtiene una visión más precisa y equilibrada de la distribución de los datos.

Además, los valores atípicos pueden influir significativamente en los modelos predictivos y algoritmos de aprendizaje automático. Si no se gestionan adecuadamente, pueden llevar a la creación de modelos ineficaces o poco precisos. Identificar y tratar estos valores atípicos permite mejorar la robustez y la generalización de los modelos, garantizando un rendimiento más confiable en datos nuevos.

# Data completa

model_data <- read.csv("C:\\Users\\Usuario\\Documents\\R_class\\Analysis_&_Manipulation_De_Datos_En_Espanol\\01_Informacion_Data\\model_data.csv")
dim(model_data)
## [1] 3466    6

Identificar valores atípicos utilizando la desviación estándar (SD)

Eliminar valores atípicos utilizando la desviación estándar (SD) es un enfoque común en estadística para identificar y tratar puntos de datos que se desvían significativamente de la media de un conjunto de datos. El método implica calcular la desviación estándar de los datos y eliminar los valores que están a una cierta distancia (múltiplos de la desviación estándar) de la media.

Aquí hay una descripción básica de cómo funciona este método:

Calcular la Media y la Desviación Estándar:

Se calcula la media (promedio) y la desviación estándar de los datos. Establecer un Umbral:

Se elige un múltiplo de la desviación estándar como umbral. Comúnmente, se utilizan múltiplos como 1, 1.5, 2, o 3, dependiendo de la rigurosidad que se desee aplicar. Identificar y Eliminar Valores Atípicos:

Se identifican los valores que están más allá del umbral establecido en ambos extremos de la distribución (por encima y por debajo de la media). Estos valores se consideran atípicos y se eliminan del conjunto de datos. Revisar y Validar:

Después de eliminar los valores atípicos, es importante revisar el conjunto de datos resultante y considerar si la exclusión de esos valores es justificada. En algunos casos, los valores atípicos pueden contener información importante o representar eventos genuinos. Es importante destacar que este método asume que los datos siguen una distribución normal.

# Calcular la media y la desviación estándar de la columna 'price' en el DataFrame 'model_data'
mean_price <- mean(model_data$price, na.rm = T)  # Calcular la media, ignorando los valores NA
sd_price <- sd(model_data$price, na.rm = T)  # Calcular la desviación estándar, ignorando los valores NA

# Identificar los valores atípicos basados en la desviación estándar (3 veces la desviación estándar)
outliers <- model_data$price < (mean_price - 3 * sd_price) | model_data$price > (mean_price + 3 * sd_price)

# Crear un nuevo DataFrame 'model1_no_outliers_sd_method' sin los valores atípicos
model1_no_outliers_sd_method <- model_data[!outliers, ]

# Mostrar información sobre el nuevo DataFrame utilizando la función 'glimpse()'
model1_no_outliers_sd_method |> glimpse()
## Rows: 3,460
## Columns: 6
## $ year          <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 20…
## $ zipCode       <int> 48221, 48221, 48221, 48221, 48221, 48221, 48221, 48221, …
## $ price         <int> 1000, 975, 1450, 1050, 1250, 1100, 1500, 1575, 1100, 120…
## $ bathrooms     <dbl> 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.5, 1.0, 1.0, 1.5, 2…
## $ bedrooms      <int> 2, 2, 5, 2, 2, 2, 2, 3, 2, 2, 4, 3, 2, 1, 3, 3, 2, 3, 3,…
## $ squareFootage <int> 1295, 1000, 1188, 2262, 1000, 1148, 879, 1400, 1143, 105…

Eliminar valores atipicos con el metodo IQR

Eliminar valores atípicos con el método IQR (rango intercuartílico) es otra técnica común en estadística. El rango intercuartílico es la diferencia entre el tercer cuartil (Q3) y el primer cuartil (Q1) de un conjunto de datos. Los valores atípicos se identifican y eliminan si están por debajo de Q1 - 1.5 * IQR o por encima de Q3 + 1.5 * IQR. Aquí hay un ejemplo de cómo implementar esto en R:

# Calcular el primer cuartil (Q1)
Q1 <- quantile(model_data$price, 0.25)

# Calcular el tercer cuartil (Q3)
Q3 <- quantile(model_data$price, 0.75)

# Calcular el rango intercuartílico (IQR)
IQR <- Q3 - Q1

# Identificar los valores atípicos utilizando el método IQR
outliers <- model_data$price < (Q1 - 1.5 * IQR) | model_data$price > (Q3 + 1.5 * IQR)

# Crear un nuevo DataFrame sin valores atípicos
model2_no_outliers_IQR_method <- model_data[!outliers, ]

# Mostrar información sobre el nuevo DataFrame sin valores atípicos
glimpse(model2_no_outliers_IQR_method)
## Rows: 3,310
## Columns: 6
## $ year          <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 20…
## $ zipCode       <int> 48221, 48221, 48221, 48221, 48221, 48221, 48221, 48221, …
## $ price         <int> 1000, 975, 1450, 1050, 1250, 1100, 1500, 1575, 1100, 120…
## $ bathrooms     <dbl> 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.5, 1.0, 1.0, 1.5, 2…
## $ bedrooms      <int> 2, 2, 5, 2, 2, 2, 2, 3, 2, 2, 4, 3, 2, 1, 3, 3, 2, 3, 3,…
## $ squareFootage <int> 1295, 1000, 1188, 2262, 1000, 1148, 879, 1400, 1143, 105…

Usar método Robustos

El Método de Desviación Absoluta de la Mediana (Median Absolute Deviation, MAD) es un enfoque robusto utilizado para identificar valores atípicos en un conjunto de datos. A diferencia de otros métodos que dependen de la media y la desviación estándar, el MAD utiliza la mediana como medida central y evalúa la dispersión de los datos en términos de desviaciones absolutas respecto a la mediana.

# Calcular la Desviación Absoluta de la Mediana (MAD)
MAD <- mad(model_data$price, constant = 1)

# Identificar valores atípicos utilizando el método robusto MAD
outliers <- abs(model_data$price - median(model_data$price)) / MAD > 2

# Crear un nuevo DataFrame sin valores atípicos utilizando el método robusto
model3_no_outliers_robust_method <- model_data[!outliers, ]

# Mostrar información sobre el nuevo DataFrame sin valores atípicos
model3_no_outliers_robust_method |> glimpse()
## Rows: 2,811
## Columns: 6
## $ year          <int> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 20…
## $ zipCode       <int> 48221, 48221, 48221, 48221, 48221, 48221, 48221, 48221, …
## $ price         <int> 1000, 975, 1450, 1050, 1250, 1100, 1500, 1575, 1100, 120…
## $ bathrooms     <dbl> 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.5, 1.0, 1.0, 1.5, 2…
## $ bedrooms      <int> 2, 2, 5, 2, 2, 2, 2, 3, 2, 2, 4, 3, 2, 1, 3, 3, 2, 3, 3,…
## $ squareFootage <int> 1295, 1000, 1188, 2262, 1000, 1148, 879, 1400, 1143, 105…

Comprobación de linealidad

La comprobación de linealidad se refiere a la evaluación de la relación entre variables en un modelo estadístico o matemático para determinar si esta relación es lineal. En el contexto de análisis de regresión, la linealidad es una suposición fundamental. La comprobación de linealidad implica asegurarse de que la relación entre la variable dependiente y las variables independientes pueda ser bien aproximada mediante una línea recta.

# Lista de variables a incluir en los gráficos de dispersión
variables <- list("bathrooms", "bedrooms", "squareFootage", "zipCode")

# Función para crear gráficos de dispersión
create_scatter_plot_fun <- function(variables) {
    ggplot(model1_no_outliers_sd_method, aes(!!sym(variables), price)) +
        geom_point() +  # Añadir puntos al gráfico
        labs(title = paste("Gráfico de dispersión de precio vs", variables),
             x = variables,
             y = "Precio")
}

# Crear una lista de gráficos utilizando la función map
plots <- map(variables, create_scatter_plot_fun)

# Organizar los gráficos en una cuadrícula
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.2.3
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
grid.arrange(plots[[1]], plots[[2]], plots[[3]], plots[[4]], ncol = 2)

# Gráficos de Residuos

Los gráficos de residuos son herramientas visuales utilizadas en el análisis de regresión para evaluar la calidad del ajuste de un modelo a los datos observados. Los residuos son las diferencias entre los valores observados y los valores predichos por el modelo. Al examinar los patrones y distribuciones de estos residuos, se pueden identificar posibles violaciones de las suposiciones del modelo de regresión.

# Lista de conjuntos de datos que contienen modelos sin valores atípicos
data_sets <- list(
  "model1_no_outliers_sd_method" = model1_no_outliers_sd_method,
  "model2_no_outliers_IQR_method" = model2_no_outliers_IQR_method,
  "model3_no_outliers_robust_method" = model3_no_outliers_robust_method
)

# Fórmula del modelo de regresión lineal
formula <- price ~ bathrooms + bedrooms + squareFootage + zipCode

# Ajustar modelos de regresión lineal a cada conjunto de datos
models <- map(data_sets, ~ lm(formula, data = .x))

# Función para crear gráficos de residuos vs valores ajustados
create_residuals_plot_fun <- function(model, model_name) {
  ggplot() +
    geom_point(aes(x = model$fitted.values, y = model$residuals)) +
    labs(
      title = paste("Residuos vs Valores Ajustados para", model_name),
      x = "Valores Ajustados",
      y = "Residuos"
    )
}

# Crear gráficos de residuos vs valores ajustados para cada modelo
plots <- map2(models, names(models), create_residuals_plot_fun)

# Organizar los gráficos en una cuadrícula de 2 columnas
grid.arrange(plots[[1]], plots[[2]], plots[[3]], ncol = 2)

## Normal Q - Q

Un Q-Q plot compara la distribución de los residuos con una distribución teórica (generalmente la distribución normal). Si los puntos del Q-Q plot siguen aproximadamente una línea diagonal, sugiere que los residuos se distribuyen de manera normal.

# Lista de modelos de regresión lineal ajustados a conjuntos de datos específicos
library(ggpubr)
## Warning: package 'ggpubr' was built under R version 4.2.3
library(cowplot)
## Warning: package 'cowplot' was built under R version 4.2.3
## 
## Attaching package: 'cowplot'
## The following object is masked from 'package:ggpubr':
## 
##     get_legend
## The following object is masked from 'package:lubridate':
## 
##     stamp
models <- list(
  "model1_no_outliers_sd_method" = lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = model1_no_outliers_sd_method),
  "model2_no_outliers_IQR_method" = lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = model2_no_outliers_IQR_method),
  "model3_no_outliers_robust_method" = lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = model3_no_outliers_robust_method)
)

# Función para crear gráficos Q-Q plot para los residuos de un modelo
create_qq_plot <- function(model_name, model) {
  residuals <- model$residuals
  qqplot <- ggqqplot(residuals) +
    ggtitle(paste("Gráfico Q-Q para", model_name))
  return(qqplot)
}

# Crear gráficos Q-Q plot para cada modelo
plots <- map2(names(models), models, create_qq_plot)

# Organizar los gráficos en una cuadrícula de 2 columnas usando plot_grid
combined_plot <- plot_grid(plotlist = plots, ncol = 2)
print(combined_plot)

Coeficiente de correlación

El coeficiente de correlación es una medida estadística que cuantifica la relación lineal entre dos variables. En otras palabras, el coeficiente de correlación indica en qué medida las variaciones en una variable están asociadas con las variaciones en otra variable. Esta medida se utiliza comúnmente para evaluar la fuerza y dirección de la relación entre dos variables continuas.

Existen diferentes tipos de coeficientes de correlación, pero uno de los más comunes es el coeficiente de correlación de Pearson. El coeficiente de correlación de Pearson, denotado como “r”, tiene un rango de -1 a 1, donde:

  • 1: Indica una correlación perfecta positiva. Esto significa que a medida que una variable aumenta, la otra variable también aumenta en una relación lineal perfecta.

  • 0: Indica ausencia de correlación lineal. No hay relación lineal entre las dos variables.

  • -1: Indica una correlación perfecta negativa. Esto significa que a medida que una variable aumenta, la otra variable disminuye en una relación lineal perfecta.

# Calcular el coeficiente de correlación entre price y bathrooms
cor_bathrooms <- cor(model1_no_outliers_sd_method$price, model1_no_outliers_sd_method$bathrooms, use = "complete.obs")
print(paste("Coeficiente de correlación entre price y bathrooms:", cor_bathrooms))
## [1] "Coeficiente de correlación entre price y bathrooms: 0.611636865410224"
# Calcular el coeficiente de correlación entre price y bedrooms
cor_bedrooms <- cor(model1_no_outliers_sd_method$price, model1_no_outliers_sd_method$bedrooms, use = "complete.obs")
print(paste("Coeficiente de correlación entre price y bedrooms:", cor_bedrooms))
## [1] "Coeficiente de correlación entre price y bedrooms: 0.269333937837847"
# Calcular el coeficiente de correlación entre price y squareFootage
cor_squareFootage <- cor(model1_no_outliers_sd_method$price, model1_no_outliers_sd_method$squareFootage, use = "complete.obs")
print(paste("Coeficiente de correlación entre price y squareFootage:", cor_squareFootage))
## [1] "Coeficiente de correlación entre price y squareFootage: 0.09230062429832"

Transformaciones de datos

Las transformaciones de datos, como tomar el logaritmo, la raíz cuadrada o elevar al cuadrado, son técnicas utilizadas en el análisis de datos por diversas razones. El propósito principal de estas transformaciones es modificar la distribución de los datos o la relación entre las variables para satisfacer las suposiciones de los métodos estadísticos o mejorar la interpretabilidad de los resultados. Aquí hay algunas razones comunes para realizar transformaciones:

  • Estabilizar la Varianza:

En el análisis de regresión, se asume que la varianza de los errores es constante en todos los niveles de las variables predictoras. Si hay una relación no constante entre la varianza y las variables predictoras, las transformaciones como la raíz cuadrada o el logaritmo pueden ayudar a estabilizar la varianza.

  • Linearizar Relaciones No Lineales:

En algunos casos, la relación entre las variables puede ser no lineal, pero los modelos estadísticos asumen una relación lineal. Tomar el logaritmo o la raíz cuadrada de una variable puede ayudar a linealizar la relación, permitiendo así que se apliquen modelos lineales.

  • Manejar Sesgo en la Distribución:

Si los datos tienen una distribución sesgada hacia la derecha, donde hay valores atípicos que se encuentran en el extremo superior, tomar el logaritmo puede reducir el sesgo y hacer que la distribución sea más simétrica.

  • Escalamiento:

Elevar al cuadrado o tomar la raíz cuadrada de una variable puede cambiar la escala de los datos, lo que puede ser útil para resaltar patrones o reducir la importancia de valores extremos.

  • Condiciones de Normalidad:

En algunos métodos estadísticos, como las pruebas de hipótesis paramétricas, se asume la normalidad de los datos. Transformaciones como el logaritmo pueden ayudar a que los datos se aproximen más a una distribución normal.

  • Mejorar la Interpretabilidad:

En ocasiones, realizar transformaciones puede hacer que los resultados sean más interpretables o más fácilmente comparables. Es importante señalar que la elección de una transformación específica depende de la naturaleza de los datos y de los objetivos del análisis. Además, se debe tener precaución al interpretar resultados transformados, ya que pueden afectar la interpretación de los coeficientes o las métricas de evaluación del modelo. La selección de una transformación adecuada a menudo implica explorar y comprender la naturaleza de los datos.

# Crear un nuevo DataFrame con la transformación logarítmica de squareFootage
m1_log <- model1_no_outliers_sd_method |>
  mutate(squareFootage = log(squareFootage))

# Crear un nuevo DataFrame con la transformación de raíz cuadrada de squareFootage
m1_sqrt <- model1_no_outliers_sd_method |>
  mutate(squareFootage = sqrt(squareFootage))

# Crear un nuevo DataFrame con la transformación cuadrática de squareFootage
m1_sq2 <-  model1_no_outliers_sd_method |>
  mutate(squareFootage = (squareFootage)^2)

# Lista de modelos de regresión lineal con diferentes transformaciones de squareFootage
models <- list(
  "model_no_outliers_sd_method" = lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = model1_no_outliers_sd_method),
  "ml_log" = lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = m1_log),
  "m1_sqrt"= lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = m1_sqrt),
  "m1_sq2" = lm(price ~ bathrooms + bedrooms + squareFootage + zipCode, data = m1_sq2)
)

# Función para crear gráficos de residuos vs valores ajustados
create_residuals_plot <- function(model_name, model) {
  ggplot() +
    geom_point(aes(x = model$fitted.values, y = model$residuals)) +
    labs(
      title = paste("Residuos vs Valores Ajustados para", model_name),
      x = "Valores Ajustados",
      y = "Residuos"
    )
}

# Crear gráficos de residuos vs valores ajustados para cada modelo
plots <- map2(names(models), models, create_residuals_plot)

# Organizar los gráficos en una cuadrícula de 2 columnas
grid.arrange(plots[[1]], plots[[2]], plots[[3]], plots[[4]], ncol = 2)